#include "MSphere.h"


MSphere::MSphere(float ar, int ars, int avs,float aox, float aoy,float aoz)
{
	name = "Sphere";
	verts = NULL;
	normal = NULL;
	bNormal = false;
	updateSphere(ar,ars,avs,aox,aoy,aoz);
}


MSphere::~MSphere(void)
{
	if(verts) {
		for(int i = 0; i<rs; i++) {
			delete []verts[i];
		}
		delete []verts;
	}
	if(normal) {
		for(int i = 0; i<rs; i++) {
			delete []normal[i];
		}
		delete []normal;
	}
}

void MSphere::drawShape() {

}

MSphere *MSphere::makeSphere(float ar, int ars, int avs,float aox, float aoy,float aoz) {
	if(ar<=0 || ars < 1 || avs < 4) {//at least 1 radial stacks and 4 vertical slice
		return NULL;
	}
	MSphere *sphere = new MSphere(ar, ars,avs,aox,aoy,aoz);
	return sphere;
}

void MSphere::updateSphere(float ar, int ars, int avs, float aox, float aoy,float aoz) {
	if(ar<=0 || ars < 1 || avs < 3) {//at least 1 radial stacks and 4 vertical slice
		return;
	}
	//delete old array
	if(verts) {
		for(int i = 0; i<rs; i++) {
			delete []verts[i];
		}
		delete []verts;
	}
	if(normal) {
		for(int i = 0; i<rs; i++) {
			delete normal[i];
		}
		delete []normal;
	}
	ox = aox;
	oy = aoy;
	oz = aoz;
	r = ar;
	rs = ars;
	vs = avs;
	step = 1;
	//create array
	verts = new MVertex*[rs];
	normal = new MVertex*[rs];
	int i, j;
	for(i = 0; i<rs; i++) {
		verts[i] = new MVertex[vs];
		normal[i] = new MVertex[vs];
	}
	//populate data
	MVertex p1(0,r,0);
	for(i = 0; i<rs; i++) {	//rotate around z axis to draw half circle
		verts[i][0] = p1.rotateZ(PI/(rs+1)*(i+1));
	}

	//rotate half circle 360 around y axis
	for(j=1; j< vs; j++) {
		float theta = 2*PI/vs;
		for(i=0; i<rs; i++) {
			verts[i][j] = verts[i][j-1].rotateY(theta);
		}
	}

	for(i=0; i<rs; i++) {
		for(j=0; j<vs; j++) {
			MVertex top = (i==0?MVertex(0,r,0):verts[i-1][j]);
			MVertex bottom = (i==(rs-1)?MVertex(0,-r,0):verts[i+1][j]);
			MVertex left = (j==0?verts[i][vs-1]:verts[i][j-1]);
			MVertex right = (j==(vs-1)?verts[i][0]:verts[i][j+1]);
			calculateNormal(&normal[i][j],verts[i][j],top,bottom,left,right);
		}
	}

}

/*func is a function to draw triangles*/
void MSphere::drawSphere(void(*func)(const MVertex &p1,  const MVertex &p2, const MVertex &p3, int ic),
			void(*drawline)(const MVertex &p1,  const MVertex &p2,int ic)) {
	static const int icolor = 5;
	if(!func) {	//return function
		return;
	}
	int i, j;
	MVertex top(0,r,0), bottom(0,-r,0);
	
	for(j=0; j < vs; j++) {
		int nextj = ((j==(vs-1))?0:(j+1));
		func(top,verts[0][nextj],verts[0][j],icolor);
		for(i=0; i<rs-1; i++) {
			func(verts[i][j],verts[i+1][j],verts[i][nextj],icolor);
			func(verts[i][nextj],verts[i+1][j],verts[i+1][nextj],icolor);
		}
		func(bottom,verts[rs-1][j],verts[rs-1][nextj],icolor);
	}
	
	if(bNormal && drawline) {
		for(i=0; i<rs; i++) {
			for(j=0; j<vs; j++) {
				drawline(verts[i][j],verts[i][j]+normal[i][j]*NORMALEN,1);
			}
		}
	}
	if(step < vs) {
		step++;
	}
}

void MSphere::resetStep() {
	step = 1;
}

bool MSphere::isComplete() const {
	return step == vs;
}

void MSphere::incrementSlice() {
	if(vs < 50) {
		this->updateSphere(r,rs,vs+1,ox,oy,oz);
	}
}

void MSphere::decrementSlice() {
	if(vs > 3) {
		this->updateSphere(r,rs,vs-1,ox,oy,oz);
	}
}

void MSphere::incrementStack() {
	if(rs < 50) {
		this->updateSphere(r,rs+1,vs,ox,oy,oz);
	}
}

void MSphere::decrementStack() {
	if(rs > 1) {
		this->updateSphere(r,rs-1,vs,ox,oy,oz);
	}
}
